use crate::i18n_text::E_UNKNOWN_CODE;
use crate::model::VddModel;
use crate::query::VddValueEvaluation;
use crate::record::VddRecord;
use crate::{datetime_format, i18n, search_type_name};
use crate::{option_datetime_format, random_str_form};
use crate::{Astr, FieldId, UserId};
use chrono::NaiveDateTime;
use serde::{Deserialize, Serialize};
use serde_json::Value;
use std::any::type_name;
use std::str::FromStr;
use std::sync::Arc;

pub const SRF_HIDE: &'static str = "SrfHide";
pub const SRF_RO: &'static str = "SrfRo";
pub const SRF_ENC: &'static str = "SrfEnc";

#[derive(Debug, Serialize, Deserialize)]
#[serde(tag = "T", content = "C")]
pub enum ShareRuleOfField {
    // 不可见列
    SrfHide(Vec<FieldId>),
    // 只读列
    SrfRo(Vec<FieldId>),
    // 加密传输的列
    SrfEnc(Vec<FieldId>),
}

impl TryFrom<&Value> for ShareRuleOfField {
    type Error = Astr;

    fn try_from(value: &Value) -> Result<Self, Self::Error> {
        let t = value["T"].as_str().unwrap_or("");
        let field_ids = value["ids"].as_array().map(|x| {
            x.iter()
                .map(|y| y.as_u64())
                .filter(|y| y.is_some())
                .map(|y| FieldId(y.unwrap()))
                .collect::<Vec<FieldId>>()
        });
        if field_ids.is_none() {
            return Err(i18n!(1301));
        }
        let field_ids = field_ids.unwrap();
        if field_ids.is_empty() {
            return Err(i18n!(1301));
        }
        match t {
            SRF_HIDE => Ok(ShareRuleOfField::SrfHide(field_ids)),
            SRF_RO => Ok(ShareRuleOfField::SrfRo(field_ids)),
            SRF_ENC => Ok(ShareRuleOfField::SrfEnc(field_ids)),
            _ => Err(i18n!(1303)),
        }
    }
}

pub const VGT_ANONYMOUS: &'static str = "VgtAnonymous";
pub const VGT_PUB_KEY: &'static str = "VgtPubKey";
pub const VGT_CODE: &'static str = "VgtCode";

/// 访问组类型 决定身份验证方式 也同时决定共享访问权限
#[derive(Debug, Serialize, Deserialize, PartialEq)]
#[serde(tag = "T", content = "C")]
pub enum VisitGroupType {
    VgtAnonymous,
    VgtPubKey,
    VgtCode { k: Astr, c: u32 },
    VgtVirtualAuthor,
}

impl TryFrom<&Value> for VisitGroupType {
    type Error = Astr;

    fn try_from(value: &Value) -> Result<Self, Self::Error> {
        let c = value["vgt"].as_str().unwrap();
        match c {
            VGT_ANONYMOUS => Ok(VisitGroupType::VgtAnonymous),
            VGT_CODE => Ok(VisitGroupType::VgtCode {
                k: VisitGroup::random_a_code(6),
                c: VisitGroup::random_v_code(6),
            }),
            VGT_PUB_KEY => Ok(VisitGroupType::VgtPubKey),
            _ => Err(i18n!(E_UNKNOWN_CODE)),
        }
    }
}

impl VisitGroupType {
    pub fn is_anon_type(&self) -> bool {
        match self {
            VisitGroupType::VgtAnonymous => true,
            _ => false,
        }
    }
    pub fn is_pub_key_type(&self) -> bool {
        match self {
            VisitGroupType::VgtPubKey => true,
            _ => false,
        }
    }
    pub fn get_name(&self) -> Astr {
        match self {
            VisitGroupType::VgtAnonymous => search_type_name(type_name::<Self>(), VGT_ANONYMOUS),
            VisitGroupType::VgtPubKey => search_type_name(type_name::<Self>(), VGT_CODE),
            VisitGroupType::VgtCode { .. } => search_type_name(type_name::<Self>(), VGT_PUB_KEY),
            _ => "".into(),
        }
    }
}

pub const SRM_V_A: &'static str = "VrAuthor";
pub const SRM_V_OVS: &'static str = "VrOtherVisitors";
pub const SRM_V_OV: &'static str = "VrVisitor";
pub const SRM_REC_MAX: &'static str = "SrmRecMax";

/// 访问数据的权限,前几个参数表示需要符合的条件，最后三个表示，是否可见，是否可修改，是否可删除
#[derive(Debug, Serialize, Deserialize, PartialEq)]
#[serde(tag = "T", content = "C")]
pub enum ShareRuleOfModel {
    VrAuthor(bool, bool, bool),
    VrOtherVisitors(bool, bool, bool),
    VrVisitor(UserId, bool, bool, bool),
    // 最多存放记录数
    SrmRecMax(usize),
}

impl TryFrom<&Value> for ShareRuleOfModel {
    type Error = Astr;

    fn try_from(value: &Value) -> Result<Self, Self::Error> {
        let t = value["T"].as_str().unwrap();
        let can_see = value["canSee"].as_bool().unwrap_or(false);
        let mut can_edit = value["canEdit"].as_bool().unwrap_or(false);
        let mut can_delete = value["canDelete"].as_bool().unwrap_or(false);
        if !can_see {
            can_edit = false;
            can_delete = false;
        }
        match t {
            SRM_V_A => Ok(Self::VrAuthor(can_see, can_edit, can_delete)),
            SRM_V_OVS => Ok(Self::VrOtherVisitors(can_see, can_edit, can_delete)),
            SRM_V_OV => {
                let u_id = value["uId"].as_u64().unwrap();
                Ok(Self::VrVisitor(UserId(u_id), can_see, can_edit, can_delete))
            }
            SRM_REC_MAX => Ok(Self::SrmRecMax(
                value["recMax"].as_u64().unwrap_or(0) as usize
            )),
            _ => Err("未知的访问权限代码".into()),
        }
    }
}

impl ShareRuleOfModel {
    pub fn fit_record(
        &self,
        record: &VddRecord,
        model_owner_id: UserId,
        visitor_id: UserId,
    ) -> Result<(bool, bool), Astr> {
        let record_owner_id = record.meta.uid.clone();
        // 自己的记录
        if record_owner_id == visitor_id {
            return Ok((true, true));
        }
        // 别人的记录，增益比对，有设置则扩展数据范围
        let check_result = match self {
            ShareRuleOfModel::VrAuthor(can_see, can_edit, can_delete) => (
                *can_see && record_owner_id == model_owner_id,
                *can_edit,
                *can_delete,
            ),
            ShareRuleOfModel::VrOtherVisitors(can_see, can_edit, can_delete) => (
                *can_see && (record_owner_id != model_owner_id) && (record_owner_id != visitor_id),
                *can_edit,
                *can_delete,
            ),
            ShareRuleOfModel::VrVisitor(uid, can_see, can_edit, can_delete) => {
                (*can_see && record_owner_id == *uid, *can_edit, *can_delete)
            }
            _ => (false, false, false),
        };
        if !check_result.0 {
            Err("权限规则不适应此条记录".into())
        } else {
            Ok((check_result.1, check_result.2))
        }
    }
}

/// 访问规则
#[derive(Debug, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct VisitGroup {
    pub model_id: u64,
    pub u_id: UserId,
    pub write_able: bool,
    pub group_type: Arc<VisitGroupType>,
    pub rule_m: Vec<Arc<ShareRuleOfModel>>,
    pub rule_f: Vec<Arc<ShareRuleOfField>>,
    pub rule_fv: Vec<Arc<VddValueEvaluation>>,
}

impl TryFrom<&Value> for VisitGroup {
    type Error = Astr;

    fn try_from(value: &Value) -> Result<Self, Self::Error> {
        let model_id = value["modelId"].as_u64().unwrap();
        let u_id = value["userId"].as_u64().unwrap_or(0);
        let u_id = UserId(u_id);
        let write_able = value["writeAble"].as_bool().unwrap_or(false);
        let group_type = VisitGroupType::try_from(value)?;
        let rights = value["rights"].as_array().map(|x| {
            x.iter()
                .map(|y| ShareRuleOfModel::try_from(y))
                .filter(|y| y.is_ok())
                .map(|y| Arc::new(y.unwrap()))
                .collect::<Vec<Arc<ShareRuleOfModel>>>()
        });
        let mut limits = Vec::<Arc<ShareRuleOfField>>::new();
        value["limits"].as_array().map(|x| {
            x.iter()
                .for_each(|y| limits.push(ShareRuleOfField::try_from(y).unwrap().into()))
        });
        let mut filters = Vec::<Arc<VddValueEvaluation>>::new();
        value["filters"].as_array().map(|x| {
            x.iter()
                .for_each(|y| filters.push(VddValueEvaluation::try_from(y).unwrap().into()))
        });
        Ok(Self {
            model_id,
            u_id,
            write_able,
            group_type: group_type.into(),
            rule_m: rights.unwrap_or(Vec::new()),
            rule_f: limits,
            rule_fv: filters,
        })
    }
}

pub(crate) const CHARSET: &'static [u8] = b"ABCDEFGHIJKLMNOPQRSTUVWXYZ";
const NUMBER_SET: &'static [u8] = b"0123456789";
impl VisitGroup {
    // 返回一个虚拟的作者访问组，用于在网关上形成作者认证结果
    pub fn fake_author_vg(model: &VddModel) -> Self {
        Self {
            model_id: model.id,
            write_able: true,
            group_type: VisitGroupType::VgtVirtualAuthor.into(),
            rule_m: Vec::new(),
            u_id: model.uid.clone(),
            rule_f: Vec::new(),
            rule_fv: Vec::new(),
        }
    }

    /// 给出一个访问组不可访问的字段id序列
    pub fn hide_field_ids(&self) -> Vec<FieldId> {
        let mut ids = Vec::<FieldId>::new();
        for limit in self.rule_f.iter() {
            match limit.as_ref() {
                ShareRuleOfField::SrfHide(field_ids) => {
                    field_ids.iter().for_each(|id| ids.push(id.clone()));
                }
                _ => {}
            }
        }
        ids
    }

    /// 给出一个访问组只读访问的字段id序列
    pub fn ro_field_ids(&self) -> Vec<FieldId> {
        let mut ids = Vec::<FieldId>::new();
        for limit in self.rule_f.iter() {
            match limit.as_ref() {
                ShareRuleOfField::SrfRo(field_ids) => {
                    field_ids.iter().for_each(|id| ids.push(id.clone()));
                }
                _ => {}
            }
        }
        ids
    }

    pub fn get_auth_status(&self, uid: &UserId) -> Astr {
        if !self.accept_anonymouse() && self.u_id != uid.clone() {
            return Arc::from("");
        }
        let mut s = self.group_type.get_name().to_string();
        s.push_str(if self.write_able {
            "，允许保存数据"
        } else {
            "，不允许保存数据"
        });
        Arc::from(s)
    }

    pub fn random_v_code(len: u8) -> u32 {
        let vcode = random_str_form(len, &NUMBER_SET);
        u32::from_str(&vcode).unwrap()
    }

    pub fn random_a_code(len: u8) -> Astr {
        let acode = random_str_form(len, &CHARSET);
        Arc::from(acode)
    }

    /// 检测访问组是否接受匿名访问
    pub fn accept_anonymouse(&self) -> bool {
        self.group_type.as_ref() == &VisitGroupType::VgtAnonymous
    }

    /// 获取访问组里的最大存放记录数限制
    pub fn visit_store_limit(&self) -> usize {
        let mut r = 0usize;
        self.rule_m.iter().for_each(|l| match l.as_ref() {
            ShareRuleOfModel::SrmRecMax(size) => r = *size,
            _ => {}
        });
        r
    }
}

#[derive(Debug, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct VisitRequest {
    pub model_id: u64,
    pub request_uid: UserId,
    pub vgt: Arc<VisitGroupType>,
    pub write_able: bool,
    pub rights: Vec<Arc<ShareRuleOfModel>>,
    #[serde(with = "datetime_format")]
    pub request_ts: NaiveDateTime,
    #[serde(with = "option_datetime_format")]
    pub accept_ts: Option<NaiveDateTime>,
    pub deny_hint: Option<Astr>,
}

impl VisitRequest {
    pub fn passed(&self) -> bool {
        self.accept_ts.is_some() && self.deny_hint.is_none()
    }
}
